#!/usr/bin/env python
#!-*-coding:utf-8

from socket import *
from collections import deque
import time
from threading import Thread
import binascii
from diagData import DiagCommand

class ChannelConnect(object):
    """
    该类主要用于和channelServer建立Diag通信通道
    """
    def __init__(self, channel_server_ip, channel_server_port, time_out):
        self._channelServer_ip = channel_server_ip
        self._channelServer_port = channel_server_port
        self._channelServer_time_out = time_out
        self._bug_size = 1024
        self.__obj = None
        self.__create_socket_connect()
        self.result_dupe = deque()
        self.diagcommand = DiagCommand()
        self.__off_cmd = ''
        self.__on_cmd = ''

        #启动server连接
        self.__start_to_connect_channel_server()


    def __create_socket_connect(self):
        address_info = (self._channelServer_ip, self._channelServer_port)
        obj = socket(AF_INET, SOCK_STREAM)
        obj.settimeout(self._channelServer_time_out)
        obj.connect(address_info)
        self.__obj = obj


    def __create_hand_shake(self):
        head1 = '000000002C00D164070000000000000000000000000000000000000000000000000000000000000000000000'
        head2 = '00 00 00 00 08 00 D1 00'
        head3 = '00 00 00 00 2C 00 D1 64 00 00 00 00 61 75 74 6F 53 61 6E 69 74 79 50 79 44 69 61 67 00 00 00 ' \
                '00 00 00 00 00 00 00 00 00 00 00 00 00'
        head4 = '00 00 00 00 08 00 63 9C'
        head5 = '00 00 00 00 08 00 63 9E'

        self.__obj.sendall(binascii.unhexlify(head1.replace(" ", "")))
        time.sleep(0.1)
        self.__obj.sendall(binascii.unhexlify(head2.replace(" ", "")))
        time.sleep(0.1)
        self.__obj.sendall(binascii.unhexlify(head3.replace(" ", "")))
        time.sleep(0.1)
        self.__obj.sendall(binascii.unhexlify(head4.replace(" ", "")))
        time.sleep(0.1)
        self.__obj.sendall(binascii.unhexlify(head5.replace(" ", "")))

    def __string_to_list__(self, data_revc, data_end):
        '''
        该函数将接受channelServer的数据报文全部转化为list，eg：['00','01'...]
        :param data_revc:
        :param data_end:
        :return:
        '''
        if len(data_end) > 0 and len(data_end[-1]) == 1:
            data_end[-1] = data_end[-1] + data_revc[0]
            data_revc = data_revc[1:]
        while len(data_revc) > 0:
            if len(data_revc) >= 2:
                data_end.append(data_revc[:2])
                data_revc = data_revc[2:]
            else:
                data_end.append(data_revc)
                data_revc = ''
        return data_end

    def __get_one_frame_data(self, rs_dupe, length):
        rs_str = ""
        for i in xrange(length):
            rs_str += rs_dupe.pop(0)
        rs_str.replace(" ", "")

        return rs_str, rs_dupe

    def __get_data_from_frame(self, one_frame):
        """
        从数据帧里面获取到数据部分
        :param one_frame: 一帧数据
        :return:
        """
        #TODO, 对于数据帧中含有0x7D的需要转化
        new_one_frame = ""
        flg = False
        for x in xrange(2, len(one_frame)+2, 2):
            sp = one_frame[x-2:x]
            if sp.upper() == "7D":
                flg = True
            elif flg == True:
                sp_new = str(hex(int("0x"+sp,16) | int(0x20)))[2:]
                sp_ = "0"+sp_new if len(sp_new) == 1 else sp_new
                new_one_frame += sp_
            else:
                new_one_frame += sp

        return new_one_frame[16:]

    def __get_data(self):
        data_list = list()
        while True:
            try:
                revc = self.__obj.recv(self._bug_size)
            except timeout:
                self.logging.syslogPf("recv time out!")

            data_list = self.__string_to_list__(binascii.hexlify(revc), data_list)

            while True:
                if len(data_list) > 5:
                    length = int("0x"+data_list[4], 16)
                    if len(data_list) < length:
                        break
                    one_frame, data_list = self.__get_one_frame_data(data_list, length)
                    self.logging.syslogPf("get all data:[{}]".format(one_frame))
                    if one_frame.upper() == '000000000800D300' or one_frame.upper() == '0000000008006301' \
                            or one_frame.upper() == '000000001000D1650700000000000000' or one_frame.lower() == '000000000c00d100d0070000':
                        continue
                    else:
                        o_f = self.__get_data_from_frame(one_frame)
                        self.logging.syslogPf("get valid data:[{}]".format(one_frame))
                        self.logging.syslogPf("dupe append:[{}]".format(o_f))
                        self.result_dupe.append(o_f)
                else:
                    break

    def __start_to_connect_channel_server(self):
        self.__create_hand_shake()
        t1 = Thread(target=self.__get_data)
        t1.setDaemon(True)
        t1.setName("antoSanity_get_data")
        t1.start()
        time.sleep(3)

    def __execute_send_command(self, cmd):
        """
        该函数用来执行发送具体命令到channelServer
        :param cmd:
        :return:
        """
        flg = False
        data = ""
        try:
            self.result_dupe.clear()
            self.logging.syslogPf("send command:[{}][{}]".format(binascii.hexlify(cmd), cmd))
            self.__obj.sendall(cmd)
            for x in xrange(10):
                time.sleep(0.5)
                if len(self.result_dupe) > 0:
                    length = len(self.result_dupe)
                    data = "".join([self.result_dupe.popleft() for i in xrange(length)])
                    flg = True
                    break


        except:
            self.logging.syslogPf("send command has except")
        finally:
            if flg:
                return flg, binascii.unhexlify(data)
            else:
                return flg, None

    def sendAtCommand(self, atCmd):
        """
        发送普通AT命令
        结果是返回两个值，第一个bool类型，表示命令是否成功执行；第二个是String类型，是命令成功执行后的返回值，执行失败，返回None
        :param atCmd:at命令
        :return:(Ture/Flase, result)
        """
        if not isinstance(atCmd, (str, unicode)):
            raise Exception("atCmd of send_at_command function must is string!")

        if not atCmd.endswith("\n") and not atCmd.endswith('\r') and not atCmd.endswith('\r\n'):
            atCmd = atCmd + "\r\n"
        elif not atCmd.endswith('\n') and atCmd.endswith('\r'):
            atCmd = atCmd + "\n"
        elif atCmd.endswith('\n') and not atCmd.endswith('\r'):
            atCmd.replace("\n", '\r\n')
        elif not atCmd.endswith("\n") and not atCmd.endswith('\r'):
            atCmd.replace()

        cmd = self.diagcommand.getAtCommand(atCmd)

        return self.__execute_send_command(cmd)


    def sendApecialAtCommand(self, atCmd):
        """
        发送特殊（以Ctri+Z结尾）的AT的命令
        结果是返回两个值，第一个bool类型，表示命令是否成功执行；第二个是String类型，是命令成功执行后的返回值，执行失败，返回None
        :param atCmd:at命令
        :return:(Ture/Flase, result)
        """
        if not isinstance(atCmd, (str, unicode)):
            raise Exception("atCmd of send_special_at_command function must is string!")

        atCmd += '\x1a'
        cmd = self.diagcommand.getAtCommand(atCmd)

        return self.__execute_send_command(cmd)

    def sendPressKeyCommand(self, pressKey=None, perssType="normal"):
        """
        该命令用来发送按键功能的diag
        执行步骤：
            1、获取按键的diag协议
            2、发送协议到channelServer
            3、接受返回的结果协议
        该函数返回一个元组，第一个表示是否成功执行命令，bool类型，第二个表示命令执行的结果（None/String）
        :param press_key:按键名称
        :param perssType:按键动作类型(normal,up,down)
        :return:(True/False, result)
        """
        if pressKey is None or not isinstance(pressKey, (str, unicode)):
            raise Exception("press_key of send_press_key_command function must is string!")
        if perssType not in ['normal', 'up', 'down']:
            raise Exception("perssType of send_press_key_command function must is normal、up or down!")
        if not self.diagcommand.check_input_press_key(pressKey):
            return False, None

        cmd = self.diagcommand.getpresskeycommand(pressKey, perssType=perssType)
        return self.__execute_send_command(cmd)

    def sendTpCommand(self):
        cmd = self.diagcommand.getTpCommand()
        return self.__execute_send_command(cmd)

    def sendDialCommand(self, phone_number):
        """
        拨打电话号码
        :param phone_number:
        :return:Ture/False
        """
        if not isinstance(phone_number, (str, unicode)) and not phone_number.isdigit():
            raise Exception("phone_number() must is digit!".format(phone_number))

        phone_number_list = list(phone_number)
        flg = False
        for pn in phone_number_list:
            flg, result = self.send_press_key_command(pressKey=pn)
            time.sleep(0.3)
            if not flg:
                return flg
        return flg

    def rebootFeaturePhone(self, second):
        """
        重启功能机
        :param second: 开机和关机之间的间隔时间
        :return:
        """
        self.power_off()
        time.sleep(second)
        self.power_on()

    def powerOff(self):
        """
        关机
        :return:
        """
        cmd = self.diagcommand.getrebootcommand(type_power="off")
        return self.__execute_send_command(cmd)

    def powerOn(self):
        """
        开机
        :return:
        """
        cmd = self.diagcommand.getrebootcommand(type_power="on")
        return self.__execute_send_command(cmd)

    def closeConnect(self):
        end = '00 00 00 00 2C 00 D1 64 01 00 00 00 61 75 74 6F 53 61 6E 69 74 79 50 79 44 69 61 67 00 00 00 ' \
              '00 00 00 00 00 00 00 00 00 00 00 00 00'
        if self.__obj is not None:
            self.__obj.sendall(end)
            self.__obj.close()
            self.__obj = None

    def __del__(self):
        if hasattr(self, "__obj") and self.__obj is not None:
            self.closeConnect()
